﻿$import( "SmitearWebGL.Core.Geometry.BoundingBox" );
$import( "SmitearWebGL.Core.Geometry.Geometry" );
$import( "SmitearWebGL.Objects.Entity" );
$import( "SmitearWebGL.Objects.ShadowMesh" );
$import( "SmitearWebGL.Programs.LightPrePass.MaterialProgram" );

SmitearWebGL.Objects.Mesh = SmitearWebGL.Objects.Entity.extend(
{
	/******** constructor ********/

	init : function()
	{
		this._super();
		this._registClass( "SmitearWebGL.Objects.Mesh" );
		
		/******** public property ********/
		
		this.extra = null;

		/******** private property ********/
		
		this._displayType = SmitearWebGL.Objects.Entity.DisplayType.MESH;
		this._vertexBuffer = null;
		this._indexBuffer = null;
		
		this._material = null;
		this._shadowMesh = null;
		this._program = null;
		this._materialProgram = null;
		this._quadTreeNode = null;
		this._boundingBox = null;
		this._vertices = null;
		this._indices = null
	}
	,

	/******** public method ********/
	
	setMaterial : function( material )
	{
		this._material = material;
		
		this._changeMaterialProgram();
	}
	,
	getVertices : function()
	{
		return this._vertices;
	}
	,
	getIndices : function()
	{
		return this._indices;
	}
	,
	getBoundingBox : function()
	{
		return this._boundingBox;
	}
	,
	getMaterial : function()
	{
		return this._material;
	}
	,
	getVertexBuffer : function()
	{
		return this._vertexBuffer;
	}
	,
	getIndexBuffer : function()
	{
		return this._indexBuffer;
	}
	,
	getShadowMesh : function()
	{
		return this._shadowMesh;
	}
	,
	getQuadTreeNode : function()
	{
		return this._quadTreeNode;
	}
	,
	setQuadTreeNode : function( quadTreeNode )
	{
		this._quadTreeNode = quadTreeNode;
	}
	,
	setProgram : function( program )
	{
		this._program = program;
	}
	,
	getProgram : function()
	{
		return this._program
	}
	,
	generateShadowMesh : function()
	{
		if ( ! this._shadowMesh )
			this._shadowMesh = this.context.objectManager.createResource( "__shadow_volume" + this.name + "__", SmitearWebGL.Objects.ShadowMesh, {shelter:this} );
		
		return this._shadowMeshes;
	}
	,
	createVertexBuffer : function( bufferData, vertexElementDescription )
	{
		if ( ! bufferData || ! vertexElementDescription ) return false;
		
		this._vertexBuffer = this.context.resourceManager.createResource( this.name + "_vb__", SmitearWebGL.Resources.VertexBuffer );
		this._vertexBuffer.bindData( bufferData );
		this._vertexBuffer.setElementDescriptions( vertexElementDescription );
		
		return true;
	}
	,
	createIndexBuffer : function( bufferData, indexElementDescription )
	{
		if ( ! bufferData || ! indexElementDescription ) return false;
		
		this._indexBuffer = this.context.resourceManager.createResource( this.name + "_ib__", SmitearWebGL.Resources.IndexBuffer );
		this._indexBuffer.bindData( bufferData );
		this._indexBuffer.setElementDescriptions( indexElementDescription );
		
		return true;
	}
	,
	updateBeforeRender : function()
	{
		this._super();
		
		this._boundingBox.transformRect( this._worldMatrix, this._worldViewProjMatrix );
		
		this._scene.getQuadTree().updateSceneObject( this );
	}
	,
	renderCallBack : function( renderEntry, activationFlags )
	{
		var hr = SmitearWebGL.Core.HResult.SUCCESS;
			
		var activationFlagBits = SmitearWebGL.Core.Render.RenderQueue.eActivationFlagBits;
		var activateSurfaceMaterial = activationFlags.testBit( activationFlagBits.k_activateSurfaceMaterial );
		var activateRenderMethod = activationFlags.testBit( activationFlagBits.k_activateRenderMethod );
		var activateModelParamA = activationFlags.testBit( activationFlagBits.k_activateModelParamA );
		var activateModelParamB = activationFlags.testBit( activationFlagBits.k_activateModelParamB );
		var program = this.context.programManager.getResourceByHandle( renderEntry.hProgram );
		
		if ( activateRenderMethod )
			hr |= program.activeShader();
		
		hr |= program.activeUniform( this );
		
		if ( activateSurfaceMaterial )
			hr |= program.activeMaterialUniform( this );
		
		if ( activateModelParamA )
		{
			hr |= this._vertexBuffer.bind();
			hr |= this._vertexBuffer.active( program.getShader() );
		}
		
		if ( activateModelParamB )
			hr |= this._indexBuffer.bind();
		
		hr |= this._indexBuffer.draw( this._material.renderMode );
		
		return hr;
	}
	,
	buildRenderEntry : function( renderQueue )
	{
		if ( ! this._material ) return SmitearWebGL.Core.HResult.UNKNOW_MATERIAL;
		if ( ! this._vertexBuffer ) return SmitearWebGL.Core.HResult.UNKNOW_VERTEX_BUFFER;
		if ( ! this._indexBuffer ) return SmitearWebGL.Core.HResult.UNKNOW_INDEX_BUFFER;
		var program = this._program || this._materialProgram;
		if ( ! program ) return SmitearWebGL.Core.HResult.UNKNOWN_PROGRAM;
		
		var pRenderEntry = renderQueue.lockRenderEntry();

		pRenderEntry.hProgram = program.getResourceHandle();
		pRenderEntry.hSurfaceMaterial = this._material.getResourceHandle();
		pRenderEntry.modelParamA = this._vertexBuffer.getResourceHandle();
		pRenderEntry.modelParamB = this._indexBuffer.getResourceHandle();
		pRenderEntry.renderObject = this;
		pRenderEntry.userData = null;

		renderQueue.unlockRenderEntry( pRenderEntry );
		
		return SmitearWebGL.Core.HResult.SUCCESS;
	}
	,
	
	/******** private method ********/

	_changeMaterialProgram : function()
	{
		var name = this.name + "_" + this._material.name;
		
		this._materialProgram = this.context.programManager.getResourceByName( name );
		
		if ( ! this._materialProgram )
		{
			this._materialProgram = this.context.programManager.createResource( name, SmitearWebGL.Programs.LightPrePass.MaterialProgram );
			this._materialProgram.generateShader( this );
		}
	}
	,
	
	/******** inherit method ********/
	
	_createResource : function( params )
	{
		this._super();
		
		this.extra = {};
		this._displayType = SmitearWebGL.Objects.Entity.DisplayType.MESH;
		this._vertexBuffer = null;
		this._indexBuffer = null;
		
		this._material = null;
		this._shadowMesh = null;
		this._program = null;
		this._materialProgram = null;
		this._quadTreeNode = null;
		this._boundingBox = new SmitearWebGL.Core.Geometry.BoundingBox();
	}
	,
	_destroyResource : function()
	{
		this._super();
			
		if ( this._shadowMesh )
			this._shadowMesh.release();
		
		this._boundingBox.release();
		this._vertexBuffer.release();
		this._indexBuffer.release();
		
		this._vertexBuffer = null;
		this._indexBuffer = null;
		this._material = null;
		this._shadowMesh = null;
		this._program = null;
		this._materialProgram = null;
		this._boundingBox = null;
		this._quadTreeNode = null;
		this._vertices = null;
		this._indices = null;
	}
}
);

/******** static property ********/

SmitearWebGL.Objects.Mesh.TRIANGLE_STRIP = 0;
SmitearWebGL.Objects.Mesh.TRIANGLES = 1;

SmitearWebGL.Objects.Mesh.Clockwise = 
{
	CW : 0,
	CCW : 1
}